#include "squares.h"
#include "figures.h"
#include "material.h"
#include "texture.h"
#define getSign(h,p) ((h)[0]*(p)[0]+(h)[1]*(p)[1]+(h)[2])
	GLfloat slidexxstep = 0.1;
	GLfloat slidexx = 0.0;


struct door_t doors[NUMBER_OF_DOORS]=
{
	//porta 1
	{{104.1,62.6},{104.9,58.4},5,CHIUSO,VERT},
	//porta 2
	{{62.4,99.9},{66.6,99.1},5,CHIUSO, HORIZ},
	//porta 3
	{{25.1,62.6},{25.9,58.4},5,CHIUSO, VERT},
	//porta 4
	{{62.4,20.9},{66.6,20.1},5,CHIUSO, HORIZ}
};



/*La funziona scandisce la struttura asMap tramite un for che arriva fino al numero di active square totali
 * e ritorna il numero dell'active square sul quale l'osservatore si trova, altrimenti torna 0
 * */
int isInActiveSquare(active_square_t* astmp,float eye_x, float eye_y){
	int i = 0;
	GLfloat x1;
	GLfloat y1;
	GLfloat x2;
	GLfloat y2;
//		printf("**********************\n");
	for (i = 0; i<NUMBER_OF_ACTIVE_SQUARE; i++){
		x1 = astmp[i].x1;
		y1 = astmp[i].y1;
		x2 = astmp[i].x2;
		y2 = astmp[i].y2;
//		printf("(%f) > (%f)\n",eye_x,x1);
//		printf("(%f) < (%f)\n",eye_y,y1);
//		printf("(%f) < (%f)\n",eye_x ,x2);
//		printf("(%f) > (%f)\n",eye_y,y2);
		if ((eye_x >= x1) 
			&& (eye_y <= y1) 
			&& (eye_x <= x2) 
			&& (eye_y >= y2)
			)
		{
//			printf("L'osservatore e' all'interno dell'area %d \n",i);
			return i;
		}
	}
//		printf("**********************\n");
	return -1;
}

void defineActiveSquare(active_square_t* astmp,
	GLfloat x1, // coordinate che definiscono il perimetro attivo della square
	GLfloat y1,
	GLfloat x2,
	GLfloat y2,
	GLint elem,
	GLint status, // 0 = non azionato / 1 = azionato
	GLint activation // 0 = non e' richiesta alcuna azione / 1 = richiesta di azionamento
		){
		astmp->x1 = x1;
		astmp->y1 = y1;
		astmp->x2 = x2;
		astmp->y2 = y2;
		astmp->elem = elem;
		astmp->status = status;
		astmp->activation = activation;
}

active_square_t* initASMap (){
	active_square_t *asMap;
	GLfloat x1,y1,x2,y2;
	GLint status, activation;
	asMap = (void*)malloc(sizeof(active_square_t) * NUMBER_OF_ACTIVE_SQUARE);
	/*inizializzo ogni elemento attivo*/

	x1 = 100.0;y1 = 65.0;
	x2 = 110.0;y2 = 55.0;
	status = 0;
	activation =0;
	defineActiveSquare(
		&asMap[PORTA_1],
		x1,y1,x2,y2, 
		PORTA_1,
		status,
		activation
	);
	
	x1 = 60.0;y1 = 105.0;
	x2 = 70.0;y2 = 95.0;
	status = 0;
	activation =0;
	defineActiveSquare(
		&asMap[PORTA_2],
		x1,y1,x2,y2, 
		PORTA_2,
		status,
		activation
	);

	x1 = 20.0;y1 = 65.0;
	x2 = 30.0;y2 = 55.0;
	defineActiveSquare(
		&asMap[PORTA_3],
		x1,y1,x2,y2, 
		PORTA_3,
		status,
		activation
	);
	
	x1 = 60.0;y1 = 25.0;
	x2 = 70.0;y2 = 15.0;
	defineActiveSquare(
		&asMap[PORTA_4],
		x1,y1,x2,y2, 
		PORTA_4,
		status,
		activation
	);
	
	return asMap;
}
void drawActiveElements(active_square_t* astmp){
	int i = 0;
	GLfloat x1,y1,x2,y2;
	for (i = 0; i<NUMBER_OF_ACTIVE_SQUARE; i++){
//		printf("Disegno elementi attivi numero :%d \n",i);
		drawElement(astmp,i);
	}
}

void drawClosedDoor(int i){
	GLfloat x1 = doors[i].start[0];
	GLfloat y1 = doors[i].start[1];
	GLfloat x2 = doors[i].end[0];
	GLfloat y2 = doors[i].end[1];
	GLfloat h = doors[i].h;
	
	drawSolidDoor(x1,y1,x2,y2,h,20 + i,doors[i].orientation);
}

void drawOpenedDoor(int i){
	GLfloat x1 = doors[i].start[0];
	GLfloat y1 = doors[i].start[1];
	GLfloat x2 = doors[i].end[0];
	GLfloat y2 = doors[i].end[1];
	GLfloat h = doors[i].h;
	GLint orientation = doors[i].orientation;
	if (orientation == HORIZ){
		//printf("ORIZZONTALE deltax=4\n");
		// sliding orizzontale
			x1 = x1 - 4;
			x2 = x2 - 4;
			drawSolidDoor(x1,y1,x2,y2,h,20 + i,doors[i].orientation);
	} else {
		//printf("VERTICALE deltax!=4\n");
		// sliding verticale
		if(slidexx <4.0){
			//printf("slidexx = %f\n",slidexx);
			y1 = y1 - 4;
			y2 = y2 - 4;
			drawSolidDoor(x1,y1,x2,y2,h,20 + i,doors[i].orientation);
		}
	}
}

int drawOpeningDoor(int i){
	GLfloat x1 = doors[i].start[0];
	GLfloat y1 = doors[i].start[1];
	GLfloat x2 = doors[i].end[0];
	GLfloat y2 = doors[i].end[1];
	GLfloat h = doors[i].h;
	GLint orientation = doors[i].orientation;
	if (orientation == HORIZ){
		//printf("ORIZZONTALE deltax=4\n");
		// sliding orizzontale
		if(slidexx<4.0){
			doors[i].start[0] -= slidexxstep;
			doors[i].end[0] -= slidexxstep;
			slidexx += slidexxstep;
			drawSolidDoor(x1,y1,x2,y2,h,20 + i,doors[i].orientation);
		}
	} else {
		//printf("VERTICALE deltax!=4\n");
		// sliding verticale
		if(slidexx <4.0){
			//printf("slidexx = %f\n",slidexx);
			doors[i].start[1] -= slidexxstep;
			doors[i].end[1] -= slidexxstep;
			slidexx += slidexxstep;
			drawSolidDoor(x1,y1,x2,y2,h,20 + i,doors[i].orientation);
		}
	}
	if (slidexx >= 4.0){
	//	printf("Porta %d aperta --> cambio status\n",i);
		doors[i].status = APERTO;
		slidexx = 0.0;
		return NON_ATTIVARE;
	}else return ATTIVARE;
}

int drawClosingDoor(int i){
	GLfloat x1 = doors[i].start[0];
	GLfloat y1 = doors[i].start[1];
	GLfloat x2 = doors[i].end[0];
	GLfloat y2 = doors[i].end[1];
	GLfloat h = doors[i].h;
	GLint orientation = doors[i].orientation;
	if (orientation == HORIZ){
		//printf("ORIZZONTALE deltax=4\n");
		// sliding orizzontale
		if(slidexx<4.0){
			doors[i].start[0] += slidexxstep;
			doors[i].end[0] += slidexxstep;
			slidexx += slidexxstep;
			drawSolidDoor(x1,y1,x2,y2,h,20 + i,doors[i].orientation);
		}
	} else {
		//printf("VERTICALE deltax!=4\n");
		// sliding verticale
		if(slidexx <4.0){
			//printf("slidexx = %f\n",slidexx);
			doors[i].start[1] += slidexxstep;
			doors[i].end[1] += slidexxstep;
			slidexx += slidexxstep;
			drawSolidDoor(x1,y1,x2,y2,h,20 + i,doors[i].orientation);
		}
	}
	if (slidexx >= 4.0){
	//	printf("Porta %d aperta --> cambio status\n",i);
		doors[i].status = CHIUSO;
		slidexx = 0.0;
		return NON_ATTIVARE;
	}else return ATTIVARE;
}

void drawActiveSquares(active_square_t* astmp){
	int i = 0;
	int act,status;
	GLfloat x1,y1,x2,y2;
	for (i = 0; i<NUMBER_OF_ACTIVE_SQUARE; i++){
		act = astmp[i].activation;
		status = doors[i].status;
		materials(&ottone);
		if ((act == ATTIVARE) && (status == CHIUSO)){
//			if (i==2)printf("ATTIVARE - CHIUSO\n");
			//disegna porta che si apre
			//modifica lo status in APERTO
			//modifica act in NON_ATTIVARE
			astmp[i].activation = drawOpeningDoor(i);
//			if (status == APERTO) {
//				printf("Attivazione square opening %d finita --> cambio ACT\n",i);
//				astmp[i].activation = CHIUSO;
//			}
		}else if ((act == ATTIVARE) && (status == APERTO)){
//			if (i==2)printf("ATTIVARE - APERTO\n");
			//disegna porta che si chiude
			//modifica lo status in CHIUSO
			//modifica act in NON_ATTIVARE
			astmp[i].activation = drawClosingDoor(i);
//			if (status == CHIUSO)  {
//				printf("Attivazione square closing %d finita --> cambio ACT\n",i);
//				astmp[i].activation = APERTO;
//			}				
		}else if ((act == NON_ATTIVARE) && (status == APERTO)){
//			if (i==2)printf("NON ATTIVARE - APERTO\n");
			//Disegna la porta aperta
//			drawOpenedDoor(i);
			drawClosedDoor(i);
		}else if ((act == NON_ATTIVARE) && (status == CHIUSO)){
			//Disegna la porta chiusa
//			if (i==2)printf("NON ATTIVARE - CHIUSO\n");
			drawClosedDoor(i);
		}
	}
}

void drawElement(active_square_t* astmp,int elem){
	GLfloat tx1,ty1,tx2,ty2;
	tx1 = astmp[elem].x1;
	ty1 = astmp[elem].y1;
	tx2 = astmp[elem].x2;
	ty2 = astmp[elem].y2;
	materials(&ottone);
	glPushMatrix();
		glTranslatef(tx1,ty1,0.0);
	glPopMatrix();
}

int acrossDoor(int i,float Start[2],float End[2])
{
	float p0[2],p1[2],p0w[2],p1w[2];
	float h0[3],h0w[3],h0s[3],h0e[3],h1[3];
	GLfloat dirp[2];
	GLfloat wsize = 1.0;
	GLint orientation = doors[i].orientation;
		p0[0]=doors[i].start[0];
		p0[1]=doors[i].start[1];

		if (orientation == HORIZ){
			//porta orizzontale
			dirp[0] = 0.0;
			dirp[1] = -1.0;
			p1[0]=doors[i].end[0];
			p1[1]=doors[i].start[1];
		}else{
			dirp[0] = 1.0;
			dirp[1] = 0.0;
			
			//porta verticale
			p1[0]=doors[i].start[0];
			p1[1]=doors[i].end[1];
		}

		p0w[0]=p0[0]+(dirp[0]*wsize);
		p0w[1]=p0[1]+(dirp[1]*wsize);

		p1w[0]=p1[0]+(dirp[0]*wsize);
		p1w[1]=p1[1]+(dirp[1]*wsize);

		findPlane(h0,p0,p1);
		findPlane(h1,Start,End);
		findPlane(h0w,p0w,p1w);
		findPlane(h0s,p0w,p0);
		findPlane(h0e,p1w,p1);

		/* given 

		     two segment SegmA:=(p,q) SegmB:=(r,s) where p,q,r,s are 2d-points
			  PlaneA which is the plane of (p,q)
			  PlaneB which is the plane of (r,s)

			the two segment intersect if and only if

			(1) the points p and q are on opposite side of PlaneB
			(2) the points r and s are on opposite side of PlaneB
		*/

		if (
(			 //test left	
			((getSign(h0e,Start)>=0 && getSign(h0e,End)<0 ) ||
				 (getSign(h0e,Start)< 0 && getSign(h0e,End)>=0)) 
			 &&
				((getSign(h1,p1w   )>=0 && getSign(h1,p1 )<0 ) ||
				 (getSign(h1,p1w  )< 0 && getSign(h1,p1)>=0))
)
|| 
(			 //test right	
			((getSign(h0s,Start)>=0 && getSign(h0s,End)<0 ) ||
				 (getSign(h0s,Start)< 0 && getSign(h0s,End)>=0)) 
			 &&
				((getSign(h1,p0w   )>=0 && getSign(h1,p0 )<0 ) ||
				 (getSign(h1,p0w  )< 0 && getSign(h1,p0)>=0))
)
|| 
( //test front	
			((getSign(h0w,Start)>=0 && getSign(h0w,End)<0 ) ||
				 (getSign(h0w,Start)< 0 && getSign(h0w,End)>=0)) 
			 &&
				((getSign(h1,p0w   )>=0 && getSign(h1,p1w )<0 ) ||
				 (getSign(h1,p0w  )< 0 && getSign(h1,p1w )>=0))
)
||
( //test back
				((getSign(h0,Start)>=0 && getSign(h0,End)<0 ) ||
				 (getSign(h0,Start)< 0 && getSign(h0,End)>=0)) 
			 &&
				((getSign(h1,p0   )>=0 && getSign(h1,p1 )<0 ) ||
				 (getSign(h1,p0   )< 0 && getSign(h1,p1 )>=0))
)
			)
		{
			return 1;
		}
	return 0;
}
